import { _decorator, Color, Component, Rect, Sprite, SpriteFrame, Texture2D, UITransform, Vec3, Vec4 } from 'cc';
const { ccclass, property } = _decorator;


@ccclass('PixelSprite')
export class PixelSprite extends Component {

    @property({ step: 1, range: [1, 1024] })
    texWidth = 128;

    @property({ step: 1, range: [1, 1024] })
    texHeight = 128;

    @property(Sprite)
    spTetris: Sprite | null = null;

    @property
    forceUpdate: boolean = true; // 是否强制每帧更新


    public isDirty: boolean = false; // 是否脏数据

    private rect: Rect = new Rect();
    private texture: Texture2D | null = null;
    private pixelData: Uint8Array | null = null;


    /**
     * 像素精灵的显示开关
     */
    set display(enable: boolean) {
        this.enabled = enable;
        if (this.spTetris) {
            this.spTetris.enabled = enable;
        }
    }


    /**
     * 全部格子区域ui大小
     */
    get totalRect() {
        let s = this.node.getWorldScale();
        let t = this.getComponent(UITransform);
        let w = t.convertToWorldSpaceAR(Vec3.ZERO);
        this.rect.set(w.x - t.width * 0.5 * s.x, w.y - t.height * 0.5 * s.y, t.width, t.height);
        return this.rect;
    }

    /**
     * 单个格子对ui大小
     */
    get gridSize() {
        let size = 1;
        let w = this.texWidth;
        let h = this.texHeight;
        let t = this.node.getComponent(UITransform);
        if (t) {
            size = t.width * 1.0 / w;
        }
        return size;
    }


    onLoad(): void {
        this.isDirty = false;
        this.texture = new Texture2D();
        this.pixelData = new Uint8Array(this.texWidth * this.texHeight * 4);
        this.texture.setFilters(Texture2D.Filter.NEAREST, Texture2D.Filter.NEAREST);
        this.texture.setWrapMode(Texture2D.WrapMode.CLAMP_TO_EDGE, Texture2D.WrapMode.CLAMP_TO_EDGE);
        this.texture.reset({ width: this.texWidth, height: this.texHeight, format: Texture2D.PixelFormat.RGBA8888, mipmapLevel: 0 });
        this.texture.uploadData(this.pixelData); // 初始化纹理数据
    }

    start() {

        // 设置到 Sprite
        if (this.spTetris) {
            let viewData = this.spTetris.material.getProperty('viewData') as Vec4;
            if (!viewData) {
                viewData = new Vec4(this.texWidth, this.texHeight, 0.5, 0.2);
            }
            viewData.x = this.texWidth, viewData.y = this.texHeight;
            this.spTetris.material.setProperty('viewData', viewData);

            let spriteFrame = this.spTetris.spriteFrame = new SpriteFrame();
            //绑定自定义纹理
            spriteFrame.texture = this.texture;
            //禁止图集打包
            spriteFrame.packable = false;
        }

    }


    /**
     * 局部更新像素数据到纹理
     * @param colors 颜色二维数组
     * @param x 起始x像素
     * @param y 起始y像素
     * @param update 是否立即刷新到GPU
     * @param force 是否强制写入所有像素
     */
    updateDatas(colors: Color[][], x: number, y: number, update: boolean = false, force: boolean = false): void {
        // 检查像素数据和纹理是否初始化
        if (!this.pixelData || !this.texture) return;

        let h = colors.length;
        let w = colors[0].length;
        // 遍历每个像素，写入到像素缓冲区
        for (let j = 0; j < h; j++) {
            for (let i = 0; i < w; i++) {
                const idx = ((j + y) * this.texWidth + (i + x)) * 4;
                const color = colors[j][i];
                // 仅在有颜色或强制模式下写入
                //@ts-ignore
                if (color._val || force) {
                    this.pixelData[idx] = color.r;
                    this.pixelData[idx + 1] = color.g;
                    this.pixelData[idx + 2] = color.b;
                    this.pixelData[idx + 3] = color.a;
                }
            }
        }

        // 标记为脏数据，等待刷新
        this.isDirty = true;
        // 立即刷新到GPU
        if (update) {
            this.isDirty = false;
            this.texture.uploadData(this.pixelData);
        }
    }


    /**
     * 整体更新纹理像素数据到GPU
     */
    updateAlldatas() {
        if (!this.pixelData || !this.texture) return;
        this.texture.uploadData(this.pixelData);
    }

    /**
     * 每帧自动刷新像素到纹理（如有脏数据或强制刷新）
     */
    lateUpdate(deltaTime: number) {
        if (this.forceUpdate || this.isDirty) {
            this.updateAlldatas();
            this.isDirty = false;
        }
    }
}


